﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace CalendarWindowsApp.Tools
{
    static public class GroupingHelper
    {
        public static IEnumerable<GroupResult> GroupByMany<TElement>(
           this IEnumerable<TElement> elements,
           params Func<TElement, object>[] groupSelectors)
        {
            if (groupSelectors.Length > 0)
            {
                var selector = groupSelectors.First();
                var nextSelectors = groupSelectors.Skip(1).ToArray();
                return
                    elements.GroupBy(selector).Select(
                        group => new GroupResult
                        {
                            Key = group.Key,
                            Count = group.Count(),
                            Items = group,
                            SubGroups = group.GroupByMany(nextSelectors)
                        });
            }
            else
                return null;
        }
        
        public static IEnumerable<GroupResult> GroupByMany<TElement>(
        this IEnumerable<TElement> elements, params string[] groupSelectors)
        {
            var selectors =
                new List<Func<TElement, object>>(groupSelectors.Length);
            groupSelectors.ForEach(group =>
            {
                var arg = Expression.Parameter(typeof(TElement), "item");
                var body = Expression.Property(arg, group);
                var lambda = Expression.Lambda<Func<TElement, object>>(body, arg);
                var keySelector = lambda.Compile();
                selectors.Add(keySelector);
            });
            return elements.GroupByMany(selectors.ToArray());
        }

        public class GroupResult
        {
            public object Key
            {
                get;
                set;
            }

            public int Count
            {
                get;
                set;
            }

            public IEnumerable Items
            {
                get;
                set;
            }

            public IEnumerable<GroupResult> SubGroups
            {
                get;
                set;
            }

            public override string ToString()
            {
                return string.Format("{0} ({1})", Key, Count);
            }
        }
    }

    static public class Extensions
    {
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (var item in source)
                action(item);
        }

        public static object GetPropertyValue(this object classObj, string propertyName)
        {
            return classObj.GetType()
                .GetTypeInfo()
                .DeclaredProperties
                .First(pi => pi.Name == propertyName)
                .GetValue(classObj);
        }

        public static Dictionary<T, string> EnumToDictionary<T>()where T : struct
        {
            Type enumType = typeof(T);
            var enumDL = new Dictionary<T, string>();
            foreach (T val in Enum.GetValues(enumType))
            {
                enumDL.Add(val, val.ToString());
            }
            return enumDL;
        }
    }
}